<?php

/*
 * 图象处理类
 */

class Image {

    /**
     * @var string $fileName 文件名
     * @access private
     */
    private $fileName = '';

    /**
     * @var gd resource $imageResource 原图像
     * @access private
     */
    private $imageResource = NULL;

    /**
     * @var int $imageWidth 原图像宽
     * @access private
     */
    public $imageWidth = NULL;

    /**
     * @var int $imageHeight 原图像高
     * @access private
     */
    public $imageHeight = NULL;

    /**
     * @var int $imageType 原图像类型
     * @access private
     */
    public $imageType = NULL;

    /**
     * @var int $newResource 新图像
     * @access private
     */
    private $newResource = NULL;

    /**
     * 构造函数
     * @param string $fileName 文件名
     */
    public function __construct($fileName = NULL) {
        $this->fileName = $fileName;
        if ($this->fileName) {
            $this->getSrcImageInfo();
        }
    }

    /**
     * 取源图像信息
     * @access private
     * @return void
     */
    private function getSrcImageInfo() {
        $info = $this->getImageInfo();
        $this->imageWidth = $info[0];
        $this->imageHeight = $info[1];
        $this->imageType = $info[2];
    }

    /**
     * 取图像信息
     * @param string $fileName 文件名
     * @access private
     * @return array
     */
    private function getImageInfo($fileName = NULL) {
        if ($fileName == NULL) {
            $fileName = $this->fileName;
        }
        $info = getimagesize($fileName);
        return $info;
    }

    /**
     * 创建源图像GD 资源
     * @access private
     * @return void
     */
    private function createSrcImage() {
        $this->imageResource = $this->createImageFromFile();
    }

    /**
     * 跟据文件创建图像GD 资源
     * @param string $fileName 文件名
     * @return gd resource
     */
    public function createImageFromFile($fileName = NULL) {
        $imgType = null;
        if (!$fileName) {
            $fileName = $this->fileName;
            $imgType = $this->imageType;
        }
        if (!is_readable($fileName) || !file_exists($fileName)) {
            throw new Exception('Unable to open file "' . $fileName . '"');
        }

        if (!$imgType) {
            $imageInfo = $this->getImageInfo($fileName);
            $imgType = $imageInfo[2];
        }

        switch ($imgType) {
            case IMAGETYPE_GIF:
                $tempResource = imagecreatefromgif($fileName);
                break;
            case IMAGETYPE_JPEG:
                $tempResource = imagecreatefromjpeg($fileName);
                break;
            case IMAGETYPE_PNG:
                $tempResource = imagecreatefrompng($fileName);
                break;
            case IMAGETYPE_WBMP:
                $tempResource = imagecreatefromwbmp($fileName);
                break;
            case IMAGETYPE_XBM:
                $tempResource = imagecreatefromxbm($fileName);
                break;
            default:
                throw new Exception('错误的图片格式，或图片有问题！');
        }
        return $tempResource;
    }

    /**
     * 改变图像大小
     * @param int $width 宽
     * @param int $height 高
     * @param string $flag 按什么方式改变 0=长宽转换成参数指定的 1=按比例缩放，长宽约束在参数指定内，2=以宽为约束缩放，3=以高为约束缩放,4按比例缩小后截取长宽部份
     * @return string
     */
    public function resizeImage($width, $height, $outputFile = null, $flag = 4) {
        $widthRatio = $width / $this->imageWidth;
        $heightRatio = $height / $this->imageHeight;
        $srcX = 0;
        $srcY = 0;
        switch ($flag) {
            case 1:
                if ($this->imageHeight < $height && $this->imageWidth < $width) {
                    $endWidth = $this->imageWidth;
                    $endHeight = $this->imageHeight;
                } elseif (($this->imageHeight * $widthRatio) > $height) {
                    $endWidth = ceil($this->imageWidth * $heightRatio);
                    $endHeight = $height;
                } else {
                    $endWidth = $width;
                    $endHeight = ceil($this->imageHeight * $widthRatio);
                }
                break;
            case 2:
                if ($this->imageWidth < $width) {
                    $endWidth = $this->imageWidth;
                    $endHeight = $this->imageHeight;
                } else {
                    $endWidth = $width;
                    $endHeight = ceil($this->imageHeight * $widthRatio);
                }
                break;
            case 3:
                if ($this->imageHeight < $height) {
                    $endWidth = $this->imageWidth;
                    $endHeight = $this->imageHeight;
                } else {
                    $endWidth = ceil($this->imageWidth * $heightRatio);
                    $endHeight = $height;
                }
                break;
            case 4:

                if ($this->imageHeight < $height && $this->imageWidth < $width) {
                    $endWidth = $this->imageWidth;
                    $endHeight = $this->imageHeight;
                } else {
                    /*
                      elseif (($this->imageHeight * $widthRatio)<$height) {
                      $endWidth = ceil($this->imageWidth * $heightRatio);
                      $endHeight = $height;
                      $srcX=Abs(($height-$this->imageHeight)/2);
                      } else {
                      $endWidth = $width;
                      $endHeight = ceil($this->imageHeight * $widthRatio);
                      $srcY=Abs(($width-$this->imageWidth)/2);
                      }
                     */
                    if (($this->imageWidth / $width) >= ($this->imageHeight / $height)) {
                        $endHeight = $height;
                        $endWidth = $this->imageWidth / ($this->imageHeight / $height);
                        $src_X = Abs(($width - $endWidth) / 2);
                        $src_Y = 0;
                    } else {
                        $endWidth = $width;
                        $endHeight = $this->imageHeight / ($this->imageWidth / $width);
                        $src_X = 0;
                        $src_Y = Abs(($height - $endHeight) / 2);
                    }
                }

                /*
                  $endWidth = $width;
                  $endHeight = $height;
                  if ($this->imageWidth < $width && $this->imageHeight < $height) {
                  $endWidth = $this->imageWidth;
                  $endHeight = $this->imageHeight;
                  } else if ($this->imageWidth < $width && $this->imageHeight > $height) {
                  $endWidth = $this->imageWidth;
                  $srcX=Abs(($height-$this->imageHeight)/2);
                  } else if ($this->imageWidth > $width && $this->imageHeight < $height) {
                  $endHeight = $this->imageHeight;
                  $srcY=Abs(($width-$this->imageWidth)/2);
                  }
                 */
                break;
            default:
                $endWidth = $width;
                $endHeight = $height;
                break;
        }
        if ($this->imageResource == NULL) {
            $this->createSrcImage();
        }

        $this->newResource = imagecreatetruecolor($endWidth, $endHeight);
        imagecopyresampled($this->newResource, $this->imageResource, 0, 0, 0, 0, $endWidth, $endHeight, $this->imageWidth, $this->imageHeight);

        if ($flag == 4 && ($endWidth != $this->imageWidth || $endHeight != $this->imageHeight)) {
            $newResource2 = imagecreatetruecolor($width, $height);
            imagecopyresampled($newResource2, $this->newResource, 0, 0, $src_X, $src_Y, $width, $height, $width, $height);
            if (!is_null($outputFile)) {
                imagejpeg($newResource2, $outputFile, 98);
            }
        } else {
            if (!is_null($outputFile)) {
                imagejpeg($this->newResource, $outputFile, 98);
            }
        }
        return true;
    }

    /*
     * 将图片转换成JPG
     */

    public function convertJPG($outputFile) {
        if ($this->imageResource == NULL) {
            $this->createSrcImage();
        }
        $this->newResource = imagecreatetruecolor($this->imageWidth, $this->imageHeight);
        imagecopyresampled($this->newResource, $this->imageResource, 0, 0, 0, 0, $this->imageWidth, $this->imageHeight, $this->imageWidth, $this->imageHeight);
        if (!is_null($outputFile)) {
            imagejpeg($this->newResource, $outputFile, 98);
        }
    }

    /*
     * 截取图片
     */

    public function clipImage($minX, $maxX, $minY, $maxY, $outputFile) {
        if ($this->imageResource == NULL) {
            $this->createSrcImage();
        }
        $endWidth = $maxX - $minX;
        $endHeight = $maxY - $minY;

        $this->newResource = imagecreatetruecolor($endWidth, $endHeight);

        imagecopyresampled($this->newResource, $this->imageResource, 0, 0, $minX, $minY, $endWidth, $endHeight, $endWidth, $endHeight);
        if (!is_null($outputFile)) {
            imagejpeg($this->newResource, $outputFile, 98);
        }
    }

    public function destroy() {
        try {
            if (!is_null($this->imageResource))
                imagedestroy($this->imageResource);
            if (!is_null($this->newResource))
                imagedestroy($this->newResource);
        } catch (exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }
    }

    /**
     * 给图像加水印
     * @param string $waterContent 水印内容可以是图像文件名，也可以是文字
     * @param int $pos 位置0-9可以是数组
     * @param int $textFont 字体大字，当水印内容是文字时有效
     * @param string $textColor 文字颜色，当水印内容是文字时有效
     * @return string
     */
    public function waterMark($waterContent, $pos = 0, $textFont = 5, $textColor = "#ffffff", $font = null) {

        $isWaterImage = file_exists($waterContent);
        if ($isWaterImage) {
            $waterImgRes = $this->createImageFromFile($waterContent);
            $waterImgInfo = $this->getImageInfo($waterContent);
            $waterWidth = $waterImgInfo[0];
            $waterHeight = $waterImgInfo[1];
        } else {
            if (is_null($font))
                throw new Exception('请指定字体文件');
            mb_language('uni');
            $waterText = $waterContent;
            $temp = @imagettfbbox($textFont, 0, $font, $waterContent);
            if ($temp) {
                $waterWidth = $temp[2] - $temp[6];
                $waterHeight = $temp[3] - $temp[7];
            } else {
                $waterWidth = 100;
                $waterHeight = 12;
            }
        }
        if ($this->imageResource == NULL) {
            $this->createSrcImage();
        }
        switch ($pos) {
            case 0://随机
                $posX = rand(0, ($this->imageWidth - $waterWidth));
                $posY = rand(0, ($this->imageHeight - $waterHeight));
                break;
            case 1://1为顶端居左
                $posX = 0;
                $posY = 0;
                break;
            case 2://2为顶端居中
                $posX = ($this->imageWidth - $waterWidth) / 2;
                $posY = 0;
                break;
            case 3://3为顶端居右
                $posX = $this->imageWidth - $waterWidth;
                $posY = 0;
                break;
            case 4://4为中部居左
                $posX = 0;
                $posY = ($this->imageHeight - $waterHeight) / 2;
                break;
            case 5://5为中部居中
                $posX = ($this->imageWidth - $waterWidth) / 2;
                $posY = ($this->imageHeight - $waterHeight) / 2;
                break;
            case 6://6为中部居右
                $posX = $this->imageWidth - $waterWidth;
                $posY = ($this->imageHeight - $waterHeight) / 2;
                break;
            case 7://7为底端居左
                $posX = 10;
                $posY = $this->imageHeight - $waterHeight - 10;
                break;
            case 8://8为底端居中
                $posX = ($this->imageWidth - $waterWidth) / 2;
                $posY = $this->imageHeight - $waterHeight;
                break;
            case 9://9为底端居右
                $posX = $this->imageWidth - $waterWidth - 10;
                $posY = $this->imageHeight - $waterHeight - 10;
                break;
            default://随机
                $posX = rand(0, ($this->imageWidth - $waterWidth));
                $posY = rand(0, ($this->imageHeight - $waterHeight));
                break;
        }
        imagealphablending($this->imageResource, true);
        if ($isWaterImage) {
            imagecopy($this->imageResource, $waterImgRes, $posX, $posY, 0, 0, $waterWidth, $waterHeight);
        } else {
            $R = hexdec(substr($textColor, 1, 2));
            $G = hexdec(substr($textColor, 3, 2));
            $B = hexdec(substr($textColor, 5));

            $textColor = imagecolorallocate($this->imageResource, $R, $G, $B);
            //imagestring($this->imageResource, $textFont, $posX, $posY, $waterText, $textColor);
            imagettftext($this->imageResource, $textFont, 0, $posX - 5, $posY + 10, $textColor, $font, $waterText);
        }
        $this->newResource = $this->imageResource;
    }

    /**
     * 生成验证码图片
     * @param int $width 宽
     * @param string $height 高
     * @param int $length 长度
     * @param int $validType 0=数字,1=字母,2=数字加字母
     * @param string $textColor 文字颜色
     * @param string $backgroundColor 背景颜色
     * @return void
     */
    public function imageValidate($width, $height, $length = 4, $validType = 1, $textColor = '#000000', $backgroundColor = '#ffffff') {
        if ($validType == 1) {
            $validString = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            $validLength = 52;
        } elseif ($validType == 2) {
            $validString = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            $validLength = 62;
        } else {
            $validString = '0123456789';
            $validLength = 10;
        }

        srand((int) time());
        $valid = '';
        for ($i = 0; $i < $length; $i++) {
            //$valid .= $validString {rand(0, $validLength - 1)};
            $valid .= $validString[rand(0, $validLength - 1)];
        }
        $this->newResource = imagecreate($width, $height);
        $bgR = hexdec(substr($backgroundColor, 1, 2));
        $bgG = hexdec(substr($backgroundColor, 3, 2));
        $bgB = hexdec(substr($backgroundColor, 5, 2));
        $backgroundColor = imagecolorallocate($this->newResource, $bgR, $bgG, $bgB);
        $tR = hexdec(substr($textColor, 1, 2));
        $tG = hexdec(substr($textColor, 3, 2));
        $tB = hexdec(substr($textColor, 5, 2));
        $textColor = imagecolorallocate($this->newResource, $tR, $tG, $tB);
        for ($i = 0; $i < strlen($valid); $i++) {
            imagestring($this->newResource, 5, $i * $width / $length + 3, 2, $valid[$i], $textColor);
        }
        return $valid;
    }

    /**
     * 显示输出图像
     * @param string $fileName 文件名
     * @param int $quality 图片质量(100最好)
     * @return void
     */
    public function display($fileName = '', $quality = 98) {

        $imgType = IMAGETYPE_JPEG;
        $imageSrc = $this->newResource;
        switch ($imgType) {
            case IMAGETYPE_GIF:
                if ($fileName == '') {
                    header('Content-type: image/gif');
                }
                imagegif($imageSrc, $fileName, $quality);
                break;
            case IMAGETYPE_JPEG:
                if ($fileName == '') {
                    header('Content-type: image/jpeg');
                }
                imagejpeg($imageSrc, $fileName, $quality);
                break;
            case IMAGETYPE_PNG:
                if ($fileName == '') {
                    header('Content-type: image/png');
                    imagepng($imageSrc);
                } else {
                    imagepng($imageSrc, $fileName);
                }
                break;
            case IMAGETYPE_WBMP:
                if ($fileName == '') {
                    header('Content-type: image/wbmp');
                }
                imagewbmp($imageSrc, $fileName, $quality);
                break;
            case IMAGETYPE_XBM:
                if ($fileName == '') {
                    header('Content-type: image/xbm');
                }
                imagexbm($imageSrc, $fileName, $quality);
                break;
            default:
                throw new Exception('Unsupport image type');
        }
        imagedestroy($imageSrc);
    }

    /**
     * 保存图像
     * @param int $fileNameType 文件名类型 0使用原文件名，1使用指定的文件名，2在原文件名加上后缀，3产生随机文件名
     * @param string $folder 文件夹路径 为空为与原文件相同
     * @param string $param 参数$fileNameType为1时为文件名2时为后缀
     * @return void
     */
    public function save($fileNameType = 0, $folder = NULL, $param = '_miniature') {
        if ($folder == NULL) {
            $folder = dirname($this->fileName) . DIRECTORY_SEPARATOR;
        }
        $fileExtName = FileSystem::fileExt($this->fileName, true);
        $fileBesicName = FileSystem::getBasicName($this->fileName, false);
        switch ($fileNameType) {
            case 1:
                $newFileName = $folder . $param;
                break;
            case 2:
                $newFileName = $folder . $fileBesicName . $param . $fileExtName;
                break;
            case 3:
                $tmp = date('YmdHis');
                $fileBesicName = $tmp;
                $i = 0;
                while (file_exists($folder . $fileBesicName . $fileExtName)) {
                    $fileBesicName = $tmp . $i;
                    $i++;
                }
                $newFileName = $folder . $fileBesicName . $fileExtName;
                break;
            default:
                $newFileName = $this->fileName;
                break;
        }
        $this->display($newFileName);
        return $newFileName;
    }

    public function upload($folder) {
        return @move_uploaded_file($this->fileName, $folder);
    }

    public function showValidImage($cookie, $cookieName) {
        $valid = $this->imageValidate(50, 20, 4, 3, '#3e3e3e', '#B6B6B6');
        $cookie->{$cookieName} = md5($valid);
        header("Cache-Control: no-cache, must-revalidate");
        $this->display();
    }

}
